#This script is just a list of utilities for the {{ project_name }} project
# -*- coding: latin-1 -*-
# from {{ module.lower() }} import {{ module }}
import re, hashlib, os, fnmatch, sys, warnings
from sqlalchemy import select, create_engine, func
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.schema import ThreadLocalMetaData

def new_session_from_engine(eng, autocommit=False):
	"""creates a new database session from an engine"""
	return scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=eng))

def new_engine(eng, output=False):
	"""creates a new database engine"""
	return create_engine(eng, echo=output)

def new_session(eng, output=False, autocommit=False):
	"""creates a new database session"""
	return scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=create_engine(eng, echo=output)))

def shasum(file_path, additional_data=None):
	"""this gets the sha512 sum of a file"""

	#open file in read binary mode
	file_handle=file(file_path,'rb')

	#new hash
	m=hashlib.sha512()

	#init data
	data = None

	#loop through bytes in file until end of file
	while True:

		#read data 1 MB at a time
		data=file_handle.read(1024*1024)

		#done reading?
		if len(data) == 0:
			break
		else:
			#otherwise update hash
			m.update(data)

	if additional_data is not None:
		m.update(str(additional_data))

	#finalize hash
	sha=m.digest()

	#close file
	file_handle.close()

	#return hash value
	return sha

def remove_unwanted_files(root_dir, file_ext):
	"""
	remove any unwanted files that meet the requirement

	usage: remove_unwanted_files('/some/dir', '.pyc') #this would remove all the '.pyc' files in /some/dir
	"""

	header = "Removing all " + file_ext + " files from " + root_dir

	print "\n " + header
	print ' ' + '=' * len(header)
	file_count = 0

	#walk the dir
	for root, dirnames, filenames in os.walk(root_dir):

		#files in dir
		for filename in fnmatch.filter(filenames, file_ext):

			#full path
			path = os.path.join(root, filename)

			#remove file
			print " Removing " + path
			os.remove(path)

			#increase file count
			file_count += 1

	print ' ' + '=' * len(header)
	print " " + str(file_count) + " " + file_ext + " files removed"

def change_host(host_ip):

	if {{ module }}.get_os() == "Windows":
		path_to_locales = {{ module }}.get_project_root()+"\config\locales.csv" #host config file
	else:
		path_to_locales = {{ module }}.get_project_root()+"/config/locales.csv" #host config file
	lines = open(path_to_locales,"r").read().splitlines() #read all lines in file		
	lines[1] = "current,"+host_ip #change the second column on the second row
	os.remove(path_to_locales) #delete existing file
	FILE = open(path_to_locales,"w") #open new file in write mode
	for line in lines: #print out all the lines again, including the changed host
		print >> FILE,line
	FILE.close #close host configuration file

	{{ module }}.set_current_host(host_ip) #lastly, set this instance of the {{ module }} module's current_host to this value

def change_analysis_event(analysis_event):

	path_to_analysis_event = os.path.normpath({{ module }}.get_project_root()+"\\config\\analysis_event_name.csv")
	
	lines = open(path_to_analysis_event,"r").read().splitlines() #read all lines in file
	lines[1] = analysis_event
	os.remove(path_to_analysis_event) #delete existing file
	FILE = open(path_to_analysis_event,"w") #open new file in write mode
	for line in lines: #print out all the lines again, including the changed test_event_name
		print >> FILE,line
	FILE.close #close analysis_event_name configuration file

	{{ module }}.set_current_analysis_event(analysis_event) #set this instance of the {{ module }} module's analysis_event_event_name to this value


def validate_analysis_event(analysis_event, usage="USAGE: (meta)make namespace:task analysis_event=example"):
	"""checks if the analysis event is in the data_directory_info.csv config file"""
	analysis_events = os.path.normpath({{ module }}.get_project_root()+"\\config\\data_directory_info.csv")

	evts = []
	with open(analysis_events, 'r') as aes:
		for ae in aes:
			if ae.startswith('#') or len(ae.strip()) < 1:
				continue
			else:
				evts.append(ae.split(',')[0])
	if not analysis_event in evts:
		print "Analysis Event was not recognized. Please add it to the data_directory_info.csv config file."
		exit()
	return True

def yes_or_no(prompt="\n Yes or no? [n] "):
	"""prompts user for yes or no"""
	_continue = raw_input(prompt)

	default = re.search(r'.*\(([a-zA-Z])+\).*', prompt)
	if default is not None:
		default = default.group(1)
	else:
		default = re.search(r'\[([a-zA-Z])+\]', prompt)
		if default is not None:
			default = default.group(1)

	if default is not None:
		if re.search("y", default, re.IGNORECASE):
			default = 'Y'
		else:
			default = 'N'
	else:
		default = 'N'

	if default == 'Y':
		if len(_continue) == 0:
			return True
	else:
		if len(_continue) == 0:
			return False
	if re.search("y", _continue, re.IGNORECASE):
		return True
	else:
		return False

def are_you_sure(prompt="\n Are you sure you want to continue?? [n] "):
	"""prompts user if they are sure"""
	return yes_or_no(prompt)
	
def data_directory_check():
	"""check if the data directory exists"""
	value = os.path.exists({{ module }}.get_data_directory())
	if not value:
		print "WARNING:  Data directory not found!"
		print "dir=" + {{ module }}.get_data_directory() + "\n"
	return value
	
#This function prints human-readable CSV output
def print_summary(rows, header=None, indention=0, output=sys.stdout, decimals=2, int_as_float=False, zfill=None):
	'''
	This prints a human readable CSV-ish document from a list of lists, with optional header and indention.
	The default output is sys.stdout, however this can be changed due to the output argument.

	The 'indentation' flag can be used to indent the output by x number of spaces.
	The 'decimals' flag sets the default number of decimal places for floats
	'''
	import decimal
	lens = []
	if header:
		if type(header) is str:
			header = [c.strip() for c in header.split(',')]
		if len(header) != len(rows[0]):
			raise Exception, "Header MUST contain the same amount of columns as the list given"
		rows.insert(0, header)
	for c in range(len(rows[0])):
		lens.append(max([len(str(t[c])) for t in rows]) + 3)

	if zfill:
		len_check = min([len(z) for z in zfill])
		if len_check < 2:
			raise Exception, "zfill argument must be a list of 2d-tuples. The first index is the column, the second is the length to zfill."
		zcols = [int(z[0]) for z in zfill]
		zlens = [int(z[1]) for z in zfill]

	for i, row in enumerate(rows):
		cols = []
		for j, col in enumerate(row):
			if re.search('^-?[0-9]+$', str(col).strip()) != None:
				try:
					if int_as_float:
						cols.append(("%%.%if" % int(decimals)) % float(str(col).strip()))
					else:
						cols.append(int(float(str(col).strip())))
				except:
					warnings.warn("'"+header[j]+"' column did not have an int value ("+str(col)+"); Set to '0'.", UserWarning, stacklevel=1)
					cols.append(0)
			elif re.search('^-?[0-9]+(.[0-9]+)?$', str(col).strip()) != None:
				try:
					cols.append(("%%.%if" % int(decimals)) % float(str(col).strip()))
				except:
					warnings.warn(header[j]+" did not have a float value ("+str(col)+"); Set to '0'.", UserWarning, stacklevel=1)
					cols.append(0.0)
			else:
				cols.append(str(col).strip())
			
			if zfill:
				if j in zcols:
					cols[-1] = str(cols[-1]).zfill(zlens[zcols.index(j)])

		s = ','.join([str(col).ljust(lens[i]) for i, col in enumerate(cols)])
		output.write(' ' * indention + s + '\n')
	output.write('\n')
	if header is not None:
		rows.pop(0)
	return 1

